﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using System.Text.RegularExpressions;
using System.IO;
using AirProperties.Resources;
using System.Globalization;

namespace AirProperties
{
    public partial class AirWizard : Form
    {

        #region Validation Regular Expressions
        //Validation regex pattens based on / adapted from validation requirements in the Descriptor.xsd files from the AIR SDK.
        private const string ID_PATTERN = @"^[A-Za-z0-9\-\.]{1,212}$";
        private const string FILENAME_PATTERN = @"^[^\*""/:&<>\?\\\|\. ]$|^[^\*""/:&<>\?\\\| ][^\*""/:&<>\?\\\|]*[^\*""/:<>\?\\\|\. ]$";
        //Minor tweak to FILEPATH_PATTERN to prevent forward slash (/) as last character (causes packaging to fail with error). 
        private const string FILEPATH_PATTERN = @"^[^\*""/:&<>\?\\\|\. ]$|^[^\*""/:&<>\?\\\| ][^\*"":&<>\?\\\|]*[^\*""/:<>\?\\\|\. ]$";
        //There is no universal standard for ANYURI_PATTERN but this pattern is a good fit for image and content 
        //URIs used in the descriptor file, as these URIs are relative paths.
        private const string ANYURI_PATTERN = @"^[^\*"":&<>\?\\\|\. ]$|^[^\*"":&<>\?\\\| ][^\*"":&<>\?\\\|]*[^\*""/:<>\?\\\|\. ]$";
        private const string COORDINATE_PATTERN = @"^(-)?\d+$";
        private const string NUMBER_PATTERN = @"^[0-9]*$";
        #endregion

        private PluginMain pluginMain;
        private String propertiesFilePath;
        private Boolean isPropertiesLoaded;
        private List<string> locales = new List<string>();
        private List<PropertyManager.AirFileType> fileTypes = new List<PropertyManager.AirFileType>();

        public Boolean IsPropertiesLoaded
        {
            get { return isPropertiesLoaded; }
        }

        public AirWizard(PluginMain pluginMain)
        {
            this.pluginMain = pluginMain;
            InitializeComponent();
            SetTitle(PluginCore.PluginBase.CurrentProject.Name);
            InitializeControls();

            if (this.pluginMain.Settings.SelectPropertiesFileOnOpen)
            {
                SelectAndLoadPropertiesFile();
            }
            else
            {
                propertiesFilePath = Path.GetDirectoryName(PluginCore.PluginBase.CurrentProject.ProjectPath);
                propertiesFilePath += @"\application.xml";
                LoadProperties(true);
            }
        }

        private void InitializeControls()
        {
            cmbSystemChrome.Items.Add(new ListItem(LocaleHelper.GetString("SystemChrome.None"), "none"));
            cmbSystemChrome.Items.Add(new ListItem(LocaleHelper.GetString("SystemChrome.Standard"), "standard"));

            openIconFileDialog.InitialDirectory = Path.GetDirectoryName(PluginCore.PluginBase.CurrentProject.ProjectPath);
            openPropertiesFileDialog.InitialDirectory = Path.GetDirectoryName(PluginCore.PluginBase.CurrentProject.ProjectPath);
        }

        private void InitializeLocales()
        {
            cmbLocales.Items.Clear();

            if (locales.Count > 0)
            {
                cmbLocales.Items.AddRange(locales.ToArray());
                pbName.Visible = true;
                pbDescription.Visible = true;
            }
            else
            {
                pbName.Visible = false;
                pbDescription.Visible = false;
                cmbLocales.Items.Add(LocaleHelper.GetString("Locale.Default"));
            }

            cmbLocales.SelectedIndex = 0;

            //if AIR 1.0 then disable locale support
            if (PropertyManager.MajorVersion == PropertyManager.AIRVersion.V10)
            {
                cmbLocales.Enabled = false;
                btnLocaleManager.Enabled = false;
                pbLocale.Visible = false;
                pbName.Visible = false;
                pbDescription.Visible = false;
            }
        }

        private String GetSelectedLocale()
        {
            String item = (String)cmbLocales.SelectedItem;
            if (item != null)
            {
                if (item == LocaleHelper.GetString("Locale.Default"))
                    return String.Empty;
                else
                    return item;
            }
            else
                return String.Empty;
        }

        private Boolean GetSelectedLocaleIsDefault()
        {
            return (Boolean)(cmbLocales.SelectedIndex == 0);
        }

        public void SetTitle(string projectName)
        {
            this.Text = projectName + " - " + LocaleHelper.GetString("Info.Title");
        }

        private void SetupUI()
        {
            //Remove unsupported properties
            if (PropertyManager.MajorVersion < PropertyManager.AIRVersion.V153)
            {
                lbPublisherID.Visible = false;
                tbPublisherID.Visible = false;
            }
            if (PropertyManager.MajorVersion < PropertyManager.AIRVersion.V20)
            {
                gbSupportedProfiles.Visible = false;
            }
        }


        private void LoadProperties(Boolean isDefault)
        {
            string contentProperty;
            string[] minSizeProperty;
            string[] maxSizeProperty;
            
            isPropertiesLoaded = false;

            if (File.Exists(propertiesFilePath))
            {
                if (PropertyManager.InitializeProperties(propertiesFilePath))
                {
                    SetupUI();

                    //Build locales list from relevant properties
                    PropertyManager.GetPropertyLocales("name", locales);
                    PropertyManager.GetPropertyLocales("description", locales);
                    InitializeLocales();

                    //Details tab
                    PropertyManager.GetProperty("id", tbID);
                    PropertyManager.GetProperty("name", tbName, GetSelectedLocale());
                    PropertyManager.GetProperty("version", tbVersion);
                    PropertyManager.GetProperty("description", tbDescription, GetSelectedLocale());
                    PropertyManager.GetProperty("copyright", tbCopyright);

                    //Installation tab
                    PropertyManager.GetAttribute("minimumPatchLevel", tbMinimumPatchLevel);
                    PropertyManager.GetProperty("filename", tbFileName);
                    PropertyManager.GetProperty("installFolder", tbInstallFolder);
                    PropertyManager.GetProperty("programMenuFolder", tbProgramMenuFolder);
                    if (PropertyManager.MajorVersion >= PropertyManager.AIRVersion.V153)
                    {
                        PropertyManager.GetProperty("publisherID", tbPublisherID);
                    }

                    //Application tab
                    PropertyManager.GetProperty("allowBrowserInvocation", cbBrowserInvocation);
                    PropertyManager.GetProperty("customUpdateUI", cbCustomUpdateUI);
                    PropertyManager.GetProperty("icon/image16x16", tbAppIcon16);
                    PropertyManager.GetProperty("icon/image32x32", tbAppIcon32);
                    PropertyManager.GetProperty("icon/image48x48", tbAppIcon48);
                    PropertyManager.GetProperty("icon/image128x128", tbAppIcon128);
                    if (PropertyManager.MajorVersion >= PropertyManager.AIRVersion.V20)
                    {
                        foreach (string val in PropertyManager.GetProperty("supportedProfiles").Split(' '))
                        {
                            if (val == "desktop")
                                cbDesktop.CheckState = CheckState.Checked;
                            else if (val == "extendedDesktop")
                                cbExtendedDesktop.CheckState = CheckState.Checked;
                            else if (val == "mobileDevice")
                                cbMobileDevice.CheckState = CheckState.Checked;
                        }
                    }

                    //Initial Window tab
                    contentProperty = PropertyManager.GetProperty("initialWindow/content");
                    tbContent.Text = System.Web.HttpUtility.UrlDecode(contentProperty);
                    PropertyManager.GetProperty("initialWindow/title", tbTitle);
                    PropertyManager.GetProperty("initialWindow/systemChrome", cmbSystemChrome, 1);
                    PropertyManager.GetProperty("initialWindow/transparent", cbTransparent);
                    PropertyManager.GetProperty("initialWindow/visible", cbVisible);
                    PropertyManager.GetProperty("initialWindow/resizable", cbResizable);
                    PropertyManager.GetProperty("initialWindow/minimizable", cbMinimizable);
                    PropertyManager.GetProperty("initialWindow/maximizable", cbMaximizable);
                    PropertyManager.GetProperty("initialWindow/x", tbX);
                    PropertyManager.GetProperty("initialWindow/y", tbY);
                    PropertyManager.GetProperty("initialWindow/width", tbWidth);
                    PropertyManager.GetProperty("initialWindow/height", tbHeight);
                    minSizeProperty = PropertyManager.GetProperty("initialWindow/minSize").Split(' ');
                    if (minSizeProperty.Length == 2)
                    {
                        tbMinSizeX.Text = minSizeProperty[0];
                        tbMinSizeY.Text = minSizeProperty[1];
                    }
                    maxSizeProperty = PropertyManager.GetProperty("initialWindow/maxSize").Split(' ');
                    if (maxSizeProperty.Length == 2)
                    {
                        tbMaxSizeX.Text = maxSizeProperty[0];
                        tbMaxSizeY.Text = maxSizeProperty[1];
                    }

                    //File Types tab
                    PropertyManager.GetFileTypes(fileTypes);
                    ValidateFileTypes();
                    InitializeFileTypesListView();

                    //Validate all controls so the error provider activates on any invalid values
                    ValidateChildren();
                    isPropertiesLoaded = true;
                }
                else
                {
                    MessageBox.Show(PropertyManager.LastException.Message, LocaleHelper.GetString("Exception.Title.Initialization"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                if (isDefault && MessageBox.Show(LocaleHelper.GetString("Alert.Message.AppDescriptorNotFound"), LocaleHelper.GetString("Alert.Title.AppDescriptorNotFound"), MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
                {
                    SelectAndLoadPropertiesFile();
                }
            }
        }

        private void SaveProperties()
        {
            string supportedProfilesProperty = String.Empty;

            if (File.Exists(propertiesFilePath))
            {
                //Details tab
                PropertyManager.SetProperty("id", tbID);
                PropertyManager.SetProperty("name", tbName, GetSelectedLocale(), GetSelectedLocaleIsDefault());
                PropertyManager.SetProperty("description", tbDescription, GetSelectedLocale(), GetSelectedLocaleIsDefault());
                PropertyManager.SetProperty("version", tbVersion);
                PropertyManager.SetProperty("copyright", tbCopyright);

                //Installation tab
                PropertyManager.SetAttribute("minimumPatchLevel", tbMinimumPatchLevel);
                PropertyManager.SetProperty("filename", tbFileName);
                PropertyManager.SetProperty("installFolder", tbInstallFolder);
                PropertyManager.SetProperty("programMenuFolder", tbProgramMenuFolder);
                if (PropertyManager.MajorVersion >= PropertyManager.AIRVersion.V153)
                {
                    PropertyManager.SetProperty("publisherID", tbPublisherID);
                }

                //Application tab
                PropertyManager.SetProperty("allowBrowserInvocation", cbBrowserInvocation);
                PropertyManager.SetProperty("customUpdateUI", cbCustomUpdateUI);
                PropertyManager.SetProperty("icon/image16x16", tbAppIcon16);
                PropertyManager.SetProperty("icon/image32x32", tbAppIcon32);
                PropertyManager.SetProperty("icon/image48x48", tbAppIcon48);
                PropertyManager.SetProperty("icon/image128x128", tbAppIcon128);
                if (PropertyManager.MajorVersion >= PropertyManager.AIRVersion.V20)
                {
                    if (cbDesktop.Checked)
                        supportedProfilesProperty += "desktop";
                    if (cbExtendedDesktop.Checked)
                    {
                        if (supportedProfilesProperty.Length > 0)
                            supportedProfilesProperty += " ";
                        supportedProfilesProperty += "extendedDesktop";
                    }
                    if (cbMobileDevice.Checked)
                    {
                        if (supportedProfilesProperty.Length > 0)
                            supportedProfilesProperty += " ";
                        supportedProfilesProperty += "mobileDevice";
                    }
                    PropertyManager.SetProperty("supportedProfiles", supportedProfilesProperty);
                }

                //Initial Window tab
                PropertyManager.SetProperty("initialWindow/content", System.Web.HttpUtility.UrlPathEncode(tbContent.Text));
                PropertyManager.SetProperty("initialWindow/title", tbTitle);
                PropertyManager.SetProperty("initialWindow/systemChrome", cmbSystemChrome);
                PropertyManager.SetProperty("initialWindow/transparent", cbTransparent);
                PropertyManager.SetProperty("initialWindow/visible", cbVisible);
                PropertyManager.SetProperty("initialWindow/resizable", cbResizable);
                PropertyManager.SetProperty("initialWindow/minimizable", cbMinimizable);
                PropertyManager.SetProperty("initialWindow/maximizable", cbMaximizable);
                PropertyManager.SetProperty("initialWindow/x", tbX);
                PropertyManager.SetProperty("initialWindow/y", tbY);
                PropertyManager.SetProperty("initialWindow/width", tbWidth);
                PropertyManager.SetProperty("initialWindow/height", tbHeight);
                PropertyManager.SetProperty("initialWindow/minSize", (tbMinSizeX.Text + " " + tbMinSizeY.Text).Trim());
                PropertyManager.SetProperty("initialWindow/maxSize", (tbMaxSizeX.Text + " " + tbMaxSizeY.Text).Trim());

                //File Types tab
                PropertyManager.SetFileTypes(fileTypes);

                PropertyManager.CommitProperties(propertiesFilePath);
            }
        }

        private void SelectAndLoadPropertiesFile()
        {
            if (openPropertiesFileDialog.ShowDialog() == DialogResult.OK)
            {
                propertiesFilePath = openPropertiesFileDialog.FileName;
                LoadProperties(false);
            }
        }

        private Boolean CheckUniformFileNamePrefix(Boolean isApplicationIcon)
        {
            Boolean isValid = true;

            if (pluginMain.Settings.UseUniformFilenames)
            {

                if (isApplicationIcon)
                {
                    if (!errorProvider1.GetError(tbFileName).Equals(String.Empty))
                    {
                        MessageBox.Show(String.Format(LocaleHelper.GetString("Alert.Message.FileNamePrefixInvalid"), "File Name"), LocaleHelper.GetString("Alert.Title.FileNamePrefixInvalid"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        isValid = false;
                    }
                }
                else
                {
                    if (!errorProvider1.GetError(tbFileTypeExtension).Equals(String.Empty))
                    {
                        MessageBox.Show(String.Format(LocaleHelper.GetString("Alert.Message.FileNamePrefixInvalid"), "Extension"), LocaleHelper.GetString("Alert.Title.FileNamePrefixInvalid"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        isValid = false;
                    }
                }
            }
            return isValid;
        }

        private void UpdateIcon(string fileName, ref TextBox fileNameTextBox, Point dimensions, Boolean isApplicationIcon)
        {

            string projectPath = Path.GetDirectoryName(PluginCore.PluginBase.CurrentProject.ProjectPath);
            string iconFolder = this.pluginMain.Settings.ProjectIconsFolder;
            string destinationPath = projectPath + @"\" + iconFolder;
            string destinationFileName;
            string packagedFileName = this.pluginMain.Settings.PackageIconsFolder;
            string filePrefix;

            if (isApplicationIcon)
            {
                filePrefix = tbFileName.Text;
            }
            else
            {
                filePrefix = tbFileTypeExtension.Text;
            }

            Bitmap img = new Bitmap(fileName);

            //first, check if the image is the correct size
            if (img.Width == dimensions.X && img.Height == dimensions.Y)
            {
                //now check if file is in path relative to project root folder
                //and if not, save to icons folder as specified by plugin settings
                if (!Path.GetDirectoryName(fileName).ToLower().Equals(destinationPath.ToLower()))
                {
                    if (pluginMain.Settings.UseUniformFilenames)
                    {
                        destinationFileName = filePrefix + dimensions.X.ToString() + Path.GetExtension(fileName);

                    }
                    else if (pluginMain.Settings.RenameIconsWithSize)
                    {
                        destinationFileName = Path.GetFileNameWithoutExtension(fileName) + dimensions.X.ToString() + Path.GetExtension(fileName);
                    }
                    else
                    {
                        destinationFileName = Path.GetFileName(fileName);
                    }

                    if (!Directory.Exists(destinationPath))
                    {
                        Directory.CreateDirectory(destinationPath);
                    }
                    File.Copy(fileName, destinationPath + @"\" + destinationFileName, true);
                }
                else
                {
                    //if inside destinationPath then just use the current filename
                    destinationFileName = Path.GetFileName(fileName);
                }

                if (packagedFileName.Length > 1)
                {
                    packagedFileName += @"/";
                }

                packagedFileName += destinationFileName;

                fileNameTextBox.Text = packagedFileName;
            }
            else
            {
                MessageBox.Show(String.Format(LocaleHelper.GetString("Alert.Message.InvalidIconDimensions"), dimensions.X.ToString(), dimensions.Y.ToString()), LocaleHelper.GetString("Alert.Title.InvalidIconDimensions"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }


        //adds the loaded file types to the list view
        private void InitializeFileTypesListView()
        {
            ListViewItem fileTypeListItem;

            lvFileTypes.SmallImageList = fileTypeStateImageList;
            fileTypeStateImageList.Images.Add(errorProvider1.Icon);

            if (fileTypes.Count > 0)
            {
                foreach (PropertyManager.AirFileType fileType in fileTypes)
                {
                    fileTypeListItem = new ListViewItem(fileType.Name);
                    fileTypeListItem.SubItems.Add(fileType.Extension);
                    if (fileType.IsValid)
                    {
                        fileTypeListItem.ToolTipText = String.Empty;
                        fileTypeListItem.ImageIndex = 0;
                    }
                    else
                    {
                        fileTypeListItem.ToolTipText = String.Format(LocaleHelper.GetString("Validation.InvalidFileType"), fileType.Name);
                        fileTypeListItem.ImageIndex = 1;
                    }
                    lvFileTypes.Items.Add(fileTypeListItem);
                }
                lvFileTypes.Items[0].Selected = true;
            }

            LoadSelectedFileType();
        }

        //gets the corresponding file type object from the list view selection
        private PropertyManager.AirFileType GetSelectedFileType()
        {
            PropertyManager.AirFileType selectedFileType = null;
            int selectedIndex = -1;

            if (lvFileTypes.SelectedIndices.Count > 0)
            {
                selectedIndex = lvFileTypes.SelectedIndices[0];
            }

            if (selectedIndex >= 0 && isPropertiesLoaded)
            {
                selectedFileType = fileTypes[selectedIndex];
            }

            return selectedFileType;
        }

        //refreshes the list view to reflect changes to the selected item
        private void RefreshSelectedFileType()
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {

                lvFileTypes.SelectedItems[0].SubItems[0].Text = selectedFileType.Name;
                lvFileTypes.SelectedItems[0].SubItems[1].Text = selectedFileType.Extension;
                if (selectedFileType.IsValid)
                {
                    lvFileTypes.SelectedItems[0].ToolTipText = String.Empty;
                    lvFileTypes.SelectedItems[0].ImageIndex = 0;
                }
                else
                {
                    lvFileTypes.SelectedItems[0].ToolTipText = String.Format(LocaleHelper.GetString("Validation.InvalidFileType"), selectedFileType.Name);
                    lvFileTypes.SelectedItems[0].ImageIndex = 1;
                }

            }
        }

        //loads the properties of the selected file type to the corresponding controls
        private void LoadSelectedFileType()
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();

            if (selectedFileType != null)
            {
                tcFileTypeDetails.Enabled = true;
                btnRemoveFileType.Enabled = true;
                tbFileTypeName.Text = selectedFileType.Name;
                tbFileTypeExtension.Text = selectedFileType.Extension;
                tbFileTypeDescription.Text = selectedFileType.Description;
                tbFileTypeContentType.Text = selectedFileType.ContentType;
                tbFileTypeIcon16.Text = selectedFileType.Icon16;
                tbFileTypeIcon32.Text = selectedFileType.Icon32;
                tbFileTypeIcon48.Text = selectedFileType.Icon48;
                tbFileTypeIcon128.Text = selectedFileType.Icon128;
            }
            else
            {
                tcFileTypeDetails.Enabled = false;
                btnRemoveFileType.Enabled = false;
                tcFileTypeDetails.SelectedTab = tpFileTypeDetails;
                tbFileTypeName.Text = "";
                tbFileTypeExtension.Text = "";
                tbFileTypeDescription.Text = "";
                tbFileTypeContentType.Text = "";
                tbFileTypeIcon16.Text = "";
                tbFileTypeIcon32.Text = "";
                tbFileTypeIcon48.Text = "";
                tbFileTypeIcon128.Text = "";
                errorProvider1.SetError(tbFileTypeName, String.Empty);
                errorProvider1.SetError(tbFileTypeExtension, String.Empty);
                errorProvider1.SetError(tbFileTypeDescription, String.Empty);
                errorProvider1.SetError(tbFileTypeContentType, String.Empty);
                errorProvider1.SetError(tbFileTypeIcon16, String.Empty);
                errorProvider1.SetError(tbFileTypeIcon32, String.Empty);
                errorProvider1.SetError(tbFileTypeIcon48, String.Empty);
                errorProvider1.SetError(tbFileTypeIcon128, String.Empty);
            }
        }


        #region Event Handlers

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {

            if (ValidateChildren())
            {
                SaveProperties();
                Close();
            }
            else
            {
                MessageBox.Show(LocaleHelper.GetString("Alert.Message.InvalidProperties"), LocaleHelper.GetString("Alert.Title.InvalidProperties"), MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }

        private void btnHelp_Click(object sender, EventArgs e)
        {
            //I don't think Adobe provide localized documentation so there's no point in localizing the help url
            System.Diagnostics.Process.Start("http://help.adobe.com/en_US/air/build/WS5b3ccc516d4fbf351e63e3d118666ade46-7ff1.html");
        }

        private void cmbSystemChrome_SelectedIndexChanged(object sender, EventArgs e)
        {
            ValidateSystemChrome();
        }

        private void btnAppIcon16_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(true) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbAppIcon16, new Point(16, 16), true);
            }
        }

        private void btnAppIcon32_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(true) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbAppIcon32, new Point(32, 32), true);
            }
        }

        private void btnAppIcon48_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(true) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbAppIcon48, new Point(48, 48), true);
            }
        }

        private void btnAppIcon128_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(true) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbAppIcon128, new Point(128, 128), true);
            }
        }

        private void cmbLocales_SelectedIndexChanged(object sender, EventArgs e)
        {
            //refresh the locale-specific properties
            if (isPropertiesLoaded)
            {
                PropertyManager.GetProperty("name", tbName, GetSelectedLocale());
                PropertyManager.GetProperty("description", tbDescription, GetSelectedLocale());
            }
        }

        private void cmbLocales_Enter(object sender, EventArgs e)
        {
            //save the locale-specific properties in case locale is about to change
            if (isPropertiesLoaded)
            {
                PropertyManager.SetProperty("name", tbName, GetSelectedLocale(), GetSelectedLocaleIsDefault());
                PropertyManager.SetProperty("description", tbDescription, GetSelectedLocale(), GetSelectedLocaleIsDefault());
            }
        }

        private void btnLocaleManager_Click(object sender, EventArgs e)
        {
            List<string> originalLocales = new List<string>();
            originalLocales.AddRange(locales);

            //Save active 
            PropertyManager.SetProperty("name", tbName, GetSelectedLocale(), GetSelectedLocaleIsDefault());
            PropertyManager.SetProperty("description", tbDescription, GetSelectedLocale(), GetSelectedLocaleIsDefault());

            LocaleManager frmLocaleMan = new LocaleManager(ref locales);
            if (frmLocaleMan.ShowDialog(this) == DialogResult.OK)
            {
                //Check to see if any locales have been removed
                foreach (string locale in originalLocales)
                {
                    if (!locales.Contains(locale))
                    {
                        //remove affected properties from properties file
                        PropertyManager.RemoveLocalizedProperty("name", locale);
                        PropertyManager.RemoveLocalizedProperty("description", locale);
                    }
                }

                //Check to see if any locales have been added
                foreach (string locale in locales)
                {
                    if (!originalLocales.Contains(locale))
                    {
                        //create the affected properties now, even though value is empty, so the locale 
                        //will be preserved if the user closes the form without specifying a value
                        PropertyManager.CreateLocalizedProperty("name", locale, (Boolean)locales[0].Equals(locale));
                        PropertyManager.CreateLocalizedProperty("description", locale, (Boolean)locales[0].Equals(locale));
                    }
                }

                //Re-initialize locales and refresh affected property fields
                InitializeLocales();
                PropertyManager.GetProperty("name", tbName, GetSelectedLocale());
                PropertyManager.GetProperty("description", tbDescription, GetSelectedLocale());
            }
            else
            {
                //reset the locales in case any changes were made
                locales.Clear();
                locales.AddRange(originalLocales);
            }
        }

        private void lvFileTypes_SelectedIndexChanged(object sender, EventArgs e)
        {
            LoadSelectedFileType();

            //Validate all controls so the error provider activates on any invalid values
            //(bit heavy handed as it does all controls - not just those for file types, but it's way easier and the performance seems fine).
            ValidateChildren();
        }

        private void btnFileTypeIcon16_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(false) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbFileTypeIcon16, new Point(16, 16), false);
                PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
                if (selectedFileType != null)
                {
                    selectedFileType.Icon16 = tbFileTypeIcon16.Text;
                }
            }
        }

        private void btnFileTypeIcon32_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(false) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbFileTypeIcon32, new Point(32, 32), false);
                PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
                if (selectedFileType != null)
                {
                    selectedFileType.Icon32 = tbFileTypeIcon32.Text;
                }
            }
        }

        private void btnFileTypeIcon48_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(false) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbFileTypeIcon48, new Point(48, 48), false);
                PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
                if (selectedFileType != null)
                {
                    selectedFileType.Icon48 = tbFileTypeIcon48.Text;
                }
            }
        }

        private void btnFileTypeIcon128_Click(object sender, EventArgs e)
        {
            if (CheckUniformFileNamePrefix(false) && openIconFileDialog.ShowDialog() == DialogResult.OK)
            {
                UpdateIcon(openIconFileDialog.FileName, ref tbFileTypeIcon128, new Point(128, 128), false);
                PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
                if (selectedFileType != null)
                {
                    selectedFileType.Icon128 = tbFileTypeIcon128.Text;
                }
            }
        }

        private void btnNewFileType_Click(object sender, EventArgs e)
        {
            //create new file type and call validate file types to set validation flags
            PropertyManager.AirFileType fileType = new PropertyManager.AirFileType();
            fileTypes.Add(fileType);
            ValidateFileTypes();

            //add the item to the list view and select it
            ListViewItem fileTypeListItem = new ListViewItem(fileType.Name);
            fileTypeListItem.SubItems.Add(fileType.Extension);
            lvFileTypes.Items.Add(fileTypeListItem);
            lvFileTypes.SelectedIndices.Clear();
            lvFileTypes.Items[lvFileTypes.Items.Count - 1].Selected = true;
            tcFileTypeDetails.SelectedTab = tpFileTypeDetails;
            RefreshSelectedFileType();
        }

        private void btnRemoveFileType_Click(object sender, EventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                fileTypes.Remove(selectedFileType);
                lvFileTypes.Items.RemoveAt(lvFileTypes.SelectedIndices[0]);
            }
        }


        #endregion

        #region Validation Event Handlers / Methods

        //Ensures that Transparent value is false and cannot 
        //be changed when System Chrome is Standard
        private void ValidateSystemChrome()
        {
            ListItem item;
            item = (ListItem)cmbSystemChrome.SelectedItem;

            if (item != null && item.Value == "standard")
            {
                cbTransparent.Checked = false;
                cbTransparent.Enabled = false;
            }
            else
            {
                cbTransparent.Enabled = true;
            }
        }


        //validates that the supplied image URI is a PNG file
        private Boolean ValidateImageExtension(String imageURI)
        {
            if (imageURI.ToLower().EndsWith(".png"))
                return true;
            else
                return false;
        }

        //loops through each loaded file type and sets initial validity flags
        //does represent a little bit of code duplication, but shit happens.
        //we need to do this is in case there are file types with invalid property values when the file is opened, or when a new file type is added
        private void ValidateFileTypes()
        {
            foreach (PropertyManager.AirFileType fileType in fileTypes)
            {
                //always true;
                fileType.DescriptionIsValid = true;

                //set validity based on validation requirements
                if (fileType.Name.Length <= 0)
                    fileType.NameIsValid = false;
                else
                    fileType.NameIsValid = true;

                if (!Regex.IsMatch(fileType.Extension, FILENAME_PATTERN))
                    fileType.ExtensionIsValid = false;
                else
                    fileType.ExtensionIsValid = true;

                if (fileType.ContentType.Length <= 0)
                    fileType.ContentTypeIsValid = false;
                else
                    fileType.ContentTypeIsValid = true;

                if (fileType.Icon16.Length > 0 && (!Regex.IsMatch(fileType.Icon16, ANYURI_PATTERN) || !ValidateImageExtension(fileType.Icon16)))
                    fileType.Icon16IsValid = false;
                else
                    fileType.Icon16IsValid = true;

                if (fileType.Icon32.Length > 0 && (!Regex.IsMatch(fileType.Icon32, ANYURI_PATTERN) || !ValidateImageExtension(fileType.Icon32)))
                    fileType.Icon32IsValid = false;
                else
                    fileType.Icon32IsValid = true;

                if (fileType.Icon48.Length > 0 && (!Regex.IsMatch(fileType.Icon48, ANYURI_PATTERN) || !ValidateImageExtension(fileType.Icon48)))
                    fileType.Icon48IsValid = false;
                else
                    fileType.Icon48IsValid = true;

                if (fileType.Icon128.Length > 0 && (!Regex.IsMatch(fileType.Icon128, ANYURI_PATTERN) || !ValidateImageExtension(fileType.Icon128)))
                    fileType.Icon128IsValid = false;
                else
                    fileType.Icon128IsValid = true;
            }
        }

        private void tbID_Validating(object sender, CancelEventArgs e)
        {
            if (!Regex.IsMatch(tbID.Text, ID_PATTERN))
            {
                this.errorProvider1.SetError(tbID, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbID.Text));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbID, "");
        }

        private void tbVersion_Validating(object sender, CancelEventArgs e)
        {
            if (tbVersion.Text.Length <= 0)
            {
                this.errorProvider1.SetError(tbVersion, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbVersion.Text));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbVersion, "");
        }

        private void tbFileName_Validating(object sender, CancelEventArgs e)
        {
            tbFileName.Text = tbFileName.Text.Trim();

            if (!Regex.IsMatch(tbFileName.Text, FILENAME_PATTERN))
            {
                this.errorProvider1.SetError(tbFileName, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbFileName.Text));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbFileName, "");
        }

        private void tbInstallFolder_Validating(object sender, CancelEventArgs e)
        {
            tbInstallFolder.Text = tbInstallFolder.Text.Trim();

            if (tbInstallFolder.Text.Length > 0 && !Regex.IsMatch(tbInstallFolder.Text, FILEPATH_PATTERN))
            {
                this.errorProvider1.SetError(tbInstallFolder, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbInstallFolder.Text));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbInstallFolder, "");
        }

        private void tbProgramMenuFolder_Validating(object sender, CancelEventArgs e)
        {
            tbProgramMenuFolder.Text = tbProgramMenuFolder.Text.Trim();

            if (tbProgramMenuFolder.Text.Length > 0 && !Regex.IsMatch(tbProgramMenuFolder.Text, FILEPATH_PATTERN))
            {
                this.errorProvider1.SetError(tbProgramMenuFolder, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbProgramMenuFolder.Text));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbProgramMenuFolder, "");
        }

        private void tbAppIcon16_Validating(object sender, CancelEventArgs e)
        {
            tbAppIcon16.Text = tbAppIcon16.Text.Trim();

            if (tbAppIcon16.Text.Length > 0 && (!Regex.IsMatch(tbAppIcon16.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbAppIcon16.Text)))
            {
                this.errorProvider1.SetError(tbAppIcon16, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 16 x 16"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbAppIcon16, "");
        }

        private void tbAppIcon32_Validating(object sender, CancelEventArgs e)
        {
            tbAppIcon32.Text = tbAppIcon32.Text.Trim();

            if (tbAppIcon32.Text.Length > 0 && (!Regex.IsMatch(tbAppIcon32.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbAppIcon32.Text)))
            {
                this.errorProvider1.SetError(tbAppIcon32, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 32 x 32"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbAppIcon32, "");
        }

        private void tbAppIcon48_Validating(object sender, CancelEventArgs e)
        {
            tbAppIcon48.Text = tbAppIcon48.Text.Trim();

            if (tbAppIcon48.Text.Length > 0 && (!Regex.IsMatch(tbAppIcon48.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbAppIcon48.Text)))
            {
                this.errorProvider1.SetError(tbAppIcon48, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 48 x 48"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbAppIcon48, "");
        }

        private void tbAppIcon128_Validating(object sender, CancelEventArgs e)
        {
            tbAppIcon128.Text = tbAppIcon128.Text.Trim();

            if (tbAppIcon128.Text.Length > 0 && (!Regex.IsMatch(tbAppIcon128.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbAppIcon128.Text)))
            {
                this.errorProvider1.SetError(tbAppIcon128, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 128 x 128"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbAppIcon128, "");
        }

        private void tbContent_Validating(object sender, CancelEventArgs e)
        {
            tbContent.Text = tbContent.Text.Trim();

            if (!Regex.IsMatch(tbContent.Text, ANYURI_PATTERN))
            {
                this.errorProvider1.SetError(tbContent, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbContent.Text));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbContent, "");
        }

        private void tbX_Validating(object sender, CancelEventArgs e)
        {
            tbX.Text = tbX.Text.Trim();

            if (tbX.Text.Length > 0 && !Regex.IsMatch(tbX.Text, COORDINATE_PATTERN))
            {
                this.errorProvider1.SetError(tbX, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbInitialLocation.Text + " (X)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbX, "");
        }

        private void tbY_Validating(object sender, CancelEventArgs e)
        {
            tbY.Text = tbY.Text.Trim();

            if (tbY.Text.Length > 0 && !Regex.IsMatch(tbY.Text, COORDINATE_PATTERN))
            {
                this.errorProvider1.SetError(tbY, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbInitialLocation.Text + " (Y)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbY, "");
        }

        private void tbWidth_Validating(object sender, CancelEventArgs e)
        {
            tbWidth.Text = tbWidth.Text.Trim();

            if (tbWidth.Text.Length > 0 && !Regex.IsMatch(tbWidth.Text, NUMBER_PATTERN))
            {
                this.errorProvider1.SetError(tbWidth, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbInitialSize.Text + " (X)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbWidth, "");
        }

        private void tbHeight_Validating(object sender, CancelEventArgs e)
        {
            tbHeight.Text = tbHeight.Text.Trim();

            if (tbHeight.Text.Length > 0 && !Regex.IsMatch(tbHeight.Text, NUMBER_PATTERN))
            {
                this.errorProvider1.SetError(tbHeight, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbInitialSize.Text + " (Y)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbHeight, "");
        }

        private void tbMinSizeX_Validating(object sender, CancelEventArgs e)
        {
            bool isValid = true;
            tbMinSizeX.Text = tbMinSizeX.Text.Trim();

            if (tbMinSizeX.Text.Length > 0)
            {
                if (!Regex.IsMatch(tbMinSizeX.Text, NUMBER_PATTERN))
                    isValid = false;
                else if (tbMaxSizeX.Text.Length > 0 && errorProvider1.GetError(tbMaxSizeX).Equals(String.Empty))
                {
                    if (Convert.ToInt32(tbMinSizeX.Text) > Convert.ToInt32(tbMaxSizeX.Text))
                        isValid = false;
                }
            }
            else if (tbMinSizeY.Text.Length > 0)
            {
                isValid = false;
            }

            if (!isValid)
            {
                this.errorProvider1.SetError(tbMinSizeX, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbMinimumSize.Text + " (X)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbMinSizeX, "");
        }

        private void tbMinSizeY_Validating(object sender, CancelEventArgs e)
        {
            bool isValid = true;
            tbMinSizeY.Text = tbMinSizeY.Text.Trim();

            if (tbMinSizeY.Text.Length > 0)
            {
                if (!Regex.IsMatch(tbMinSizeY.Text, NUMBER_PATTERN))
                    isValid = false;
                else if (tbMaxSizeY.Text.Length > 0 && errorProvider1.GetError(tbMaxSizeY).Equals(String.Empty))
                {
                    if (Convert.ToInt32(tbMinSizeY.Text) > Convert.ToInt32(tbMaxSizeY.Text))
                        isValid = false;
                }
            }
            else if (tbMinSizeX.Text.Length > 0)
            {
                isValid = false;
            }

            if (!isValid)
            {
                this.errorProvider1.SetError(tbMinSizeY, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbMinimumSize.Text + " (Y)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbMinSizeY, "");
        }

        private void tbMaxSizeX_Validating(object sender, CancelEventArgs e)
        {
            bool isValid = true;
            tbMaxSizeX.Text = tbMaxSizeX.Text.Trim();

            if (tbMaxSizeX.Text.Length > 0)
            {
                if (!Regex.IsMatch(tbMaxSizeX.Text, NUMBER_PATTERN))
                    isValid = false;
                else if (tbMinSizeX.Text.Length > 0 && errorProvider1.GetError(tbMinSizeX).Equals(String.Empty))
                {
                    if (Convert.ToInt32(tbMaxSizeX.Text) < Convert.ToInt32(tbMinSizeX.Text))
                        isValid = false;
                }
            }
            else if (tbMaxSizeY.Text.Length > 0)
            {
                isValid = false;
            }

            if (!isValid)
            {
                this.errorProvider1.SetError(tbMaxSizeX, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbMaximumSize.Text + " (X)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbMaxSizeX, "");
        }

        private void tbMaxSizeY_Validating(object sender, CancelEventArgs e)
        {
            bool isValid = true;
            tbMaxSizeY.Text = tbMaxSizeY.Text.Trim();

            if (tbMaxSizeY.Text.Length > 0)
            {
                if (!Regex.IsMatch(tbMaxSizeY.Text, NUMBER_PATTERN))
                    isValid = false;
                else if (tbMinSizeY.Text.Length > 0 && errorProvider1.GetError(tbMinSizeY).Equals(String.Empty))
                {
                    if (Convert.ToInt32(tbMaxSizeY.Text) < Convert.ToInt32(tbMinSizeY.Text))
                        isValid = false;
                }
            }
            else if (tbMaxSizeX.Text.Length > 0)
            {
                isValid = false;
            }

            if (!isValid)
            {
                this.errorProvider1.SetError(tbMaxSizeY, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbMaximumSize.Text + " (Y)"));
                e.Cancel = true;
            }
            else
                this.errorProvider1.SetError(tbMaxSizeY, "");
        }

        private void tbFileTypeName_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeName.Text = tbFileTypeName.Text.Trim();

                selectedFileType.Name = tbFileTypeName.Text;

                if (tbFileTypeName.Text.Length <= 0)
                {
                    selectedFileType.NameIsValid = false;
                    this.errorProvider1.SetError(tbFileTypeName, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbFTName.Text));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.NameIsValid = true;
                    this.errorProvider1.SetError(tbFileTypeName, "");
                }

                RefreshSelectedFileType();
            }
        }

        private void tbFileTypeExtension_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeExtension.Text = tbFileTypeExtension.Text.Trim();
                tbFileTypeExtension.Text = tbFileTypeExtension.Text.Trim('.');

                selectedFileType.Extension = tbFileTypeExtension.Text;

                if (!Regex.IsMatch(tbFileTypeExtension.Text, FILENAME_PATTERN))
                {
                    selectedFileType.ExtensionIsValid = false;
                    this.errorProvider1.SetError(tbFileTypeExtension, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbFTExtension.Text));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.ExtensionIsValid = true;
                    this.errorProvider1.SetError(tbFileTypeExtension, "");
                }


                RefreshSelectedFileType();
            }
        }

        private void tbFileTypeDescription_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeDescription.Text = tbFileTypeDescription.Text.Trim();
                selectedFileType.Description = tbFileTypeDescription.Text;
            }
        }

        private void tbFileTypeContentType_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeContentType.Text = tbFileTypeContentType.Text.Trim();

                selectedFileType.ContentType = tbFileTypeContentType.Text;

                //validate as required field for AIR 1.5+
                if (tbFileTypeContentType.Text.Length <= 0 && PropertyManager.MajorVersion >= PropertyManager.AIRVersion.V15)
                {
                    selectedFileType.ContentTypeIsValid = false;
                    this.errorProvider1.SetError(tbFileTypeContentType, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), lbFTContentType.Text));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.ContentTypeIsValid = true;
                    this.errorProvider1.SetError(tbFileTypeContentType, "");
                }
                RefreshSelectedFileType();
            }
        }

        private void tbFileTypeIcon16_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeIcon16.Text = tbFileTypeIcon16.Text.Trim();
                selectedFileType.Icon16 = tbFileTypeIcon16.Text;

                if (tbFileTypeIcon16.Text.Length > 0 && (!Regex.IsMatch(tbFileTypeIcon16.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbFileTypeIcon16.Text)))
                {
                    selectedFileType.Icon16IsValid = false;
                    this.errorProvider1.SetError(tbFileTypeIcon16, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 16 x 16"));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.Icon16IsValid = true;
                    this.errorProvider1.SetError(tbFileTypeIcon16, String.Empty);
                }
                RefreshSelectedFileType();
            }
        }

        private void tbFileTypeIcon32_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeIcon32.Text = tbFileTypeIcon32.Text.Trim();
                selectedFileType.Icon32 = tbFileTypeIcon32.Text;

                if (tbFileTypeIcon32.Text.Length > 0 && (!Regex.IsMatch(tbFileTypeIcon32.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbFileTypeIcon32.Text)))
                {
                    selectedFileType.Icon32IsValid = false;
                    this.errorProvider1.SetError(tbFileTypeIcon32, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 32 x 32"));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.Icon32IsValid = true;
                    this.errorProvider1.SetError(tbFileTypeIcon32, String.Empty);
                }
                RefreshSelectedFileType();
            }
        }

        private void tbFileTypeIcon48_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeIcon48.Text = tbFileTypeIcon48.Text.Trim();
                selectedFileType.Icon48 = tbFileTypeIcon48.Text;

                if (tbFileTypeIcon48.Text.Length > 0 && (!Regex.IsMatch(tbFileTypeIcon48.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbFileTypeIcon48.Text)))
                {
                    selectedFileType.Icon48IsValid = false;
                    this.errorProvider1.SetError(tbFileTypeIcon48, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 48 x 48"));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.Icon48IsValid = true;
                    this.errorProvider1.SetError(tbFileTypeIcon48, String.Empty);
                }
                RefreshSelectedFileType();
            }
        }

        private void tbFileTypeIcon128_Validating(object sender, CancelEventArgs e)
        {
            PropertyManager.AirFileType selectedFileType = GetSelectedFileType();
            if (selectedFileType != null)
            {
                tbFileTypeIcon128.Text = tbFileTypeIcon128.Text.Trim();
                selectedFileType.Icon128 = tbFileTypeIcon128.Text;

                if (tbFileTypeIcon128.Text.Length > 0 && (!Regex.IsMatch(tbFileTypeIcon128.Text, ANYURI_PATTERN) || !ValidateImageExtension(tbFileTypeIcon128.Text)))
                {
                    selectedFileType.Icon128IsValid = false;
                    this.errorProvider1.SetError(tbFileTypeIcon128, String.Format(LocaleHelper.GetString("Validation.InvalidProperty"), LocaleHelper.GetString("Label.Icon") + " 128 x 128"));
                    e.Cancel = true;
                }
                else
                {
                    selectedFileType.Icon128IsValid = true;
                    this.errorProvider1.SetError(tbFileTypeIcon128, String.Empty);
                }
                RefreshSelectedFileType();
            }
        }

        private void lvFileTypes_Validating(object sender, CancelEventArgs e)
        {
            foreach (PropertyManager.AirFileType fileType in fileTypes)
            {
                if (!fileType.IsValid)
                {
                    e.Cancel = true;
                    break;
                }
            }
        }

        private void tbPublisherID_Validating(object sender, CancelEventArgs e)
        {
            tbPublisherID.Text = tbPublisherID.Text.Trim();
        }

        #endregion
        
    }
}
